package pe.com.casadesign.dao.impl;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcCall;
import org.springframework.stereotype.Repository;

import pe.com.casadesign.dao.SolicitudDAO;
import pe.com.casadesign.domain.Bulto;
import pe.com.casadesign.domain.LineaSolicitud;
import pe.com.casadesign.domain.LineaSolicitudBulto;
import pe.com.casadesign.domain.ListaItem;
import pe.com.casadesign.domain.ListaLineaSolicitud;
import pe.com.casadesign.domain.ListaLineaSolicitudBulto;
import pe.com.casadesign.domain.ListaLineaSolicitudItem;
import pe.com.casadesign.domain.LineaSolicitudItem;
import pe.com.casadesign.domain.ListaSolicitud;
import pe.com.casadesign.domain.Prestamo;
import pe.com.casadesign.domain.Producto;
import pe.com.casadesign.domain.Solicitud;
import pe.com.casadesign.domain.Tienda;
import pe.com.casadesign.domain.Usuario;
import pe.com.casadesign.domain.Item;
import pe.com.casadesign.domain.Moneda;

/**
 * Implementacion de SolicitudDAO.
 * 
 * @author Pedro Vera
 * 
 */
@Repository
public class SolicitudDAOImpl implements SolicitudDAO {
	private static final Logger logger = LoggerFactory.getLogger(SolicitudDAOImpl.class);
	
	// Nombre Procedimientos Almacenados
	private static String SP_LISTAR_SOLICITUD = "SP_LISTAR_SOLICITUD";
	private static String SP_OBTENER_SOLICITUD = "SP_OBTENER_SOLICITUD";
	private static String SP_OBTENER_SOLICITUD_ITEM = "SP_OBTENER_SOLICITUD_ITEM";
	private static String SP_REGISTRAR_SOLICITUD = "SP_REGISTRAR_SOLICITUD";
	private static String SP_REGISTRAR_DET_SOLICITUD = "SP_REGISTRAR_DET_SOLICITUD";
	private static String SP_REGISTRAR_DET_SOLICITUD_ITEM = "SP_REGISTRAR_DET_SOLICITUD_ITEM";
	private static String SP_REGISTRAR_DET_SOLICITUD_BULTO = "SP_REGISTRAR_DET_SOLICITUD_BULTO";
	private static String SP_ACTUALIZAR_ESTADO_ITEM = "SP_ACTUALIZAR_ESTADO_ITEM";
	private static String SP_ACTUALIZAR_ESTADO_BULTO = "SP_ACTUALIZAR_ESTADO_BULTO";
	private static String SP_LIMPIAR_DET_SOLICITUD_ITEM = "SP_LIMPIAR_DET_SOLICITUD_ITEM";
	private static String SP_MODIFICAR_SOLICITUD = "SP_MODIFICAR_SOLICITUD";
	private static String SP_LIMPIAR_DET_SOLICITUD = "SP_LIMPIAR_DET_SOLICITUD";
	private static String SP_ACTUALIZAR_ESTADO_SOLICITUD = "SP_ACTUALIZAR_ESTADO_SOLICITUD";
	private static String SP_ACTUALIZAR_SOLICITUD = "SP_ACTUALIZAR_SOLICITUD";
	private static String SP_LIMPIAR_DET_SOLICITUD_BULTO = "SP_LIMPIAR_DET_SOLICITUD_BULTO";
	private static String SP_ACTUALIZAR_OBSERVACIONES_SOLICITUD = "SP_ACTUALIZAR_OBSERVACIONES_SOLICITUD";
	
	// Parametros de Entrada
	private static String PARAM_CODSOLICITUD = "p_codsolicitud";
	private static String PARAM_CODUSUARIO = "p_codusuario";
	private static String PARAM_CODTIENDAORIGEN = "p_codtiendaorigen";
	private static String PARAM_CODTIENDADESTINO = "p_codtiendadestino";
	private static String PARAM_TIPO = "p_tipo";
	private static String PARAM_FECHAVENCIMIENTO = "p_fechavencimiento";
	private static String PARAM_OBSERVACION = "p_observacion";
	private static String PARAM_ESTADO = "p_estado";
	private static String PARAM_CODUSUARIOAPROVACION = "p_codusuarioaprovacion";
	private static String PARAM_FECHAAPROVACION = "p_fechaaprovacion";
	
	private static String PARAM_DET_CODPRODUCTO = "p_codproducto";
	private static String PARAM_DET_CANTIDAD = "p_cantidad";
	
	private static String PARAM_BULTO_CODBULTO = "p_codbulto";
	private static String PARAM_BULTO_ESTADO = "p_estado";
	private static String PARAM_BULTO_TIENDA  = "p_codtienda";
	
	private static String PARAM_ITEM_CODITEM = "p_coditem";
	private static String PARAM_ITEM_ESTADO = "p_estado";	
	
	// Parametros de Salida
	private static String CODSOLICITUD = "CODSOLICITUD";
	private static String CODUSUARIO = "CODUSUARIO";
	private static String CODUSUARIOAPROVACION = "CODUSUARIOAPROVACION";
	private static String CODTIENDAORIGEN = "CODTIENDAORIGEN";
	private static String CODTIENDADESTINO = "CODTIENDADESTINO";
	private static String TIPO = "TIPO";
	private static String FECHAVENCIMIENTO = "FECHAVENCIMIENTO";
	private static String FECHAAPROVACION = "FECHAAPROVACION";
	private static String OBSERVACION = "OBSERVACION";
	private static String ESTADO = "ESTADO";
	private static String FECHAREGISTRO = "FECHAREGISTRO";
	
	private static String USUARIO_NOMBRESYAPELLIDOS = "NOMBRESYAPELLIDOS";
	
	private static String TIENDA_ORIGEN_NOMBRE = "DESTIENDAORIGEN";
	private static String TIENDA_DESTINO_NOMBRE = "DESTIENDADESTINO";
	
	private static String PRODUCTO_DESCRIPCION = "DESCRIPCION";
	
	private static String DET_CODPRODUCTO = "CODPRODUCTO";
	private static String DET_CODPRODUCTOPROVEEDOR = "CODPRODUCTOPROVEEDOR";
	private static String DET_CANTIDAD = "CANTIDAD";
	
	private static String BULTO_CODBULTO = "CODBULTO";
	private static String BULTO_SSCC = "SSCC";
		
	private static String ITEM_CODITEM = "CODITEM";
	private static String ITEM_CODIFICACION = "CODIFICACION";
	private static String ITEM_PRECIOCOMPRA = "PRECIOCOMPRA";
	private static String ITEM_CODMONEDA = "CODMONEDA";
	private static String ITEM_CODTIENDA ="CODTIENDA";
	private static String ITEM_ESTADO ="ESTADO";
	
	private static String LISTADO = "LISTADO";
	private static String LISTADO_LINEAS = "LISTADO_LINEAS";
	private static String LISTADO_BULTOS = "LISTADO_BULTOS";
	private static String LISTADO_LINEAS_ITEM = "LISTADO_LINEAS_ITEM";
	
	private static String TOTAL_FILAS_AFECTADAS = "#update-count-1";
	
	private JdbcTemplate jdbcTemplate;
	
	@Autowired
    public void setDataSource(DataSource dataSource)
    {
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }
	
	@Override
	public ListaSolicitud listarSolicitud(Solicitud solicitud) {
		logger.info("listarSolicitud");

		// Instanciando variable para llamado de SP
	    SimpleJdbcCall llamarSP = new SimpleJdbcCall(jdbcTemplate).withProcedureName(SP_LISTAR_SOLICITUD).
	    						  returningResultSet(LISTADO, new RowMapper<Solicitud>(){
									@Override
									public Solicitud mapRow(final ResultSet rs, final int numRow) throws SQLException
								    {
								        final Solicitud solicitud = new Solicitud();
								        solicitud.setCodSolicitud(rs.getInt(CODSOLICITUD));
								        
								        Tienda tiendaOrigen =  new Tienda();
								        tiendaOrigen.setCodigo(rs.getInt(CODTIENDAORIGEN));
								        tiendaOrigen.setNombre(rs.getString(TIENDA_ORIGEN_NOMBRE));
								        solicitud.setTiendaOrigen(tiendaOrigen);
								        
								        Tienda tiendaDestino =  new Tienda();
								        tiendaDestino.setCodigo(rs.getInt(CODTIENDADESTINO));
								        tiendaDestino.setNombre(rs.getString(TIENDA_DESTINO_NOMBRE));
								        solicitud.setTiendaDestino(tiendaDestino);
								        
								        solicitud.setTipo(rs.getString(TIPO));
								        
								        Usuario usuario = new Usuario();
								        usuario.setCodUsuario(rs.getInt(CODUSUARIO));
								        usuario.setNombresyApellidos(rs.getString(USUARIO_NOMBRESYAPELLIDOS));
								        solicitud.setUsuario(usuario);
								        
								        Usuario usuarioAprovacion = new Usuario();
								        usuarioAprovacion.setCodUsuario(rs.getInt(CODUSUARIOAPROVACION));
								        solicitud.setUsuarioAprovacion(usuarioAprovacion);
								        
								        solicitud.setFechaVencimiento(rs.getString(FECHAVENCIMIENTO));
								        solicitud.setObservacion(rs.getString(OBSERVACION));
								        
								        solicitud.setEstado(rs.getString(ESTADO));
								        solicitud.setFechaRegistro(rs.getDate(FECHAREGISTRO).toString());
								        solicitud.setFechaAprovacion(rs.getDate(FECHAAPROVACION)==null?null:rs.getDate(FECHAAPROVACION).toString());
								        
								        return solicitud;
								    }
	    						  }
								);

	    // Estableciendo parametros de entrada al SP
	    SqlParameterSource parametros = new MapSqlParameterSource()
	    								.addValue(PARAM_CODTIENDAORIGEN, solicitud.getTiendaOrigen().getCodigo())
	    								.addValue(PARAM_TIPO, solicitud.getTipo())
	    								.addValue(PARAM_ESTADO, solicitud.getEstado()); 

	    // Establecer parametros y ejecutar SP
        Map<String,Object> data = llamarSP.execute(parametros);

        // Obteniendo lista generada de ejecutar SP
		@SuppressWarnings("unchecked")
		List<Solicitud> listaSolicitud = (List<Solicitud>)data.get(LISTADO);
        
		// Instanciando objeto ListaSolicitud
		ListaSolicitud listaSolicitudResultado = new ListaSolicitud();
        // Estableciendo resultado al objeto listaSolicitudResultado
		listaSolicitudResultado.setLista(listaSolicitud);
        
        if (logger.isDebugEnabled() && listaSolicitudResultado != null)
        {
            logger.debug("size=" + listaSolicitudResultado.size());
        }
        return listaSolicitudResultado;
	}

	@Override
	public Solicitud obtenerSolicitud(Solicitud solicitud) {
		logger.info("obtenerSolicitud");

		// Instanciando variable para llamado de SP
	    SimpleJdbcCall llamarSP = new SimpleJdbcCall(jdbcTemplate).withProcedureName(SP_OBTENER_SOLICITUD).
	    						  returningResultSet(LISTADO, new RowMapper<Solicitud>(){
									@Override
									public Solicitud mapRow(final ResultSet rs, final int numRow) throws SQLException
								    {
								        final Solicitud solicitud = new Solicitud();
								        solicitud.setCodSolicitud(rs.getInt(CODSOLICITUD));
								        
								        Tienda tiendaOrigen =  new Tienda();
								        tiendaOrigen.setCodigo(rs.getInt(CODTIENDAORIGEN));
								        tiendaOrigen.setNombre(rs.getString(TIENDA_ORIGEN_NOMBRE));
								        solicitud.setTiendaOrigen(tiendaOrigen);
								        
								        Tienda tiendaDestino =  new Tienda();
								        tiendaDestino.setCodigo(rs.getInt(CODTIENDADESTINO));
								        tiendaDestino.setNombre(rs.getString(TIENDA_DESTINO_NOMBRE));
								        solicitud.setTiendaDestino(tiendaDestino);
								        
								        solicitud.setTipo(rs.getString(TIPO));
								        
								        Usuario usuario = new Usuario();
								        usuario.setCodUsuario(rs.getInt(CODUSUARIO));
								        usuario.setNombresyApellidos(rs.getString(USUARIO_NOMBRESYAPELLIDOS));
								        solicitud.setUsuario(usuario);
								        
								        Usuario usuarioAprovacion = new Usuario();
								        usuarioAprovacion.setCodUsuario(rs.getInt(CODUSUARIOAPROVACION));
								        solicitud.setUsuarioAprovacion(usuarioAprovacion);
								        
								        solicitud.setFechaVencimiento(rs.getString(FECHAVENCIMIENTO));
								        solicitud.setObservacion(rs.getString(OBSERVACION));
								        
								        solicitud.setEstado(rs.getString(ESTADO));
								        solicitud.setFechaRegistro(rs.getDate(FECHAREGISTRO).toString());
								        solicitud.setFechaAprovacion(rs.getDate(FECHAAPROVACION)==null?null:rs.getDate(FECHAAPROVACION).toString());
								        return solicitud;
								    }
	    						  }
								 )
								 .returningResultSet(LISTADO_LINEAS, new RowMapper<LineaSolicitud>(){
									@Override
									public LineaSolicitud mapRow(final ResultSet rs, final int numRow) throws SQLException
								    {
								        final LineaSolicitud lineaSolicitud = new LineaSolicitud();
								        lineaSolicitud.setCodigoSolicitud(rs.getInt(CODSOLICITUD));
								        
								        Producto producto = new Producto();
								        producto.setCodigo(rs.getInt(DET_CODPRODUCTO));
								        producto.setCodProductoProveedor(rs.getString(DET_CODPRODUCTOPROVEEDOR));
								        producto.setDescripcion(rs.getString(PRODUCTO_DESCRIPCION));
								        lineaSolicitud.setProducto(producto);
								        
								        lineaSolicitud.setCantidad(rs.getInt(DET_CANTIDAD));
	
								        return lineaSolicitud;
								    }
	    						 }
								 )
	    						 .returningResultSet(LISTADO_BULTOS, new RowMapper<LineaSolicitudBulto>() {
    							    @Override
									public LineaSolicitudBulto mapRow(final ResultSet rs, final int numRow) throws SQLException
								    {
								        final LineaSolicitudBulto lineaSolicitudBulto = new LineaSolicitudBulto();
								        lineaSolicitudBulto.setCodigoSolicitud(rs.getInt(CODSOLICITUD));
								        
								        Bulto bulto = new Bulto();
								        bulto.setCodBulto(rs.getInt(BULTO_CODBULTO));
								        bulto.setSSCC(rs.getString(BULTO_SSCC));
								        lineaSolicitudBulto.setBulto(bulto);
	
								        return lineaSolicitudBulto;
								    }
								});

	    // Estableciendo parametros de entrada al SP
	    SqlParameterSource parametros = new MapSqlParameterSource()
	    								.addValue(PARAM_CODSOLICITUD, solicitud.getCodSolicitud()); 

	    // Establecer parametros y ejecutar SP
        Map<String,Object> data = llamarSP.execute(parametros);

        // Obteniendo lista generada de ejecutar SP
 		@SuppressWarnings("unchecked")
 		List<Solicitud> listaSolicitud = (List<Solicitud>)data.get(LISTADO);
         
 		// Declarando objeto solicitud Obtenido
 		Solicitud solicitudObtenido = null;
 		
 		if (logger.isDebugEnabled() && listaSolicitud != null)
        {
            logger.debug("size=" + listaSolicitud.size());
        }
 		
 		if (listaSolicitud != null && listaSolicitud.size()>0){
 			// Obteniendo el primer elemento de la lista de solicitud
 			solicitudObtenido = listaSolicitud.get(0);
 		
	        // Obteniendo lista de lineas generada de ejecutar SP
			@SuppressWarnings("unchecked")
			List<LineaSolicitud> listaLineaSolicitud = (List<LineaSolicitud>)data.get(LISTADO_LINEAS);
	        
			// Instanciando objeto ListaLineaSolicitud
			ListaLineaSolicitud listaLineaSolicitudResultado = new ListaLineaSolicitud();
	        // Estableciendo resultado al objeto listaLineaSolicitudResultado
			listaLineaSolicitudResultado.setLista(listaLineaSolicitud);
	        
			// Asignando lista de lineas al objeto solicitudObtenido creado
			solicitudObtenido.setListaLineaSolicitud(listaLineaSolicitudResultado);
			
	        if (logger.isDebugEnabled() && listaLineaSolicitudResultado != null)
	        {
	            logger.debug("sizeLineas=" + listaLineaSolicitudResultado.size());
	        }
	        
	        // Obteniendo lista de bultos generada de ejecutar SP
			@SuppressWarnings("unchecked")
			List<LineaSolicitudBulto> listaLineaSolicitudBulto = (List<LineaSolicitudBulto>)data.get(LISTADO_BULTOS);
	        
			// Instanciando objeto ListaLineaSolicitudBulto
			ListaLineaSolicitudBulto listaLineaSolicitudBultoResultado = new ListaLineaSolicitudBulto();
	        // Estableciendo resultado al objeto listaLineaSolicitudBultoResultado
			listaLineaSolicitudBultoResultado.setLista(listaLineaSolicitudBulto);
	        
			// Asignando lista de bultos al objeto solicitudObtenido creado
			solicitudObtenido.setListaLineaSolicitudBulto(listaLineaSolicitudBultoResultado);
			
	        if (logger.isDebugEnabled() && listaLineaSolicitudBultoResultado != null)
	        {
	            logger.debug("sizeBultos=" + listaLineaSolicitudBultoResultado.size());
	        }
 		}
        return solicitudObtenido;
	}
	
	@Override
	public boolean registrarSolicitud(Solicitud solicitud) {
		logger.info("registrarSolicitud");
		
		int resultado = 0;
		
		// Instanciando variable para llamado de SP
	    SimpleJdbcCall llamarSP = new SimpleJdbcCall(jdbcTemplate)
	    							  .withProcedureName(SP_REGISTRAR_SOLICITUD);

	    // Estableciendo parametros de entrada al SP
	    SqlParameterSource parametros = new MapSqlParameterSource()
	    								.addValue(PARAM_CODUSUARIO, solicitud.getUsuario().getCodUsuario())
	    								.addValue(PARAM_CODTIENDAORIGEN, solicitud.getTiendaOrigen().getCodigo())
	    								.addValue(PARAM_CODTIENDADESTINO, solicitud.getTiendaDestino().getCodigo())
	    								.addValue(PARAM_TIPO, solicitud.getTipo())
	    								.addValue(PARAM_FECHAVENCIMIENTO, solicitud.getFechaVencimiento())
	    								.addValue(PARAM_OBSERVACION, solicitud.getObservacion())
	    								.addValue(PARAM_ESTADO, solicitud.getEstado());
	    
	    // Establecer parametros y ejecutar SP
	    Map<String,Object> data = llamarSP.execute(parametros);
	    
	    // Obteniendo el total de filas afectadas al ejecutar SP
	    resultado += (Integer) data.get(TOTAL_FILAS_AFECTADAS);
	    
	    logger.debug("codigo generado:" + data.get(PARAM_CODSOLICITUD));

	    // Obteniendo codigo de solicitud
	    int codigoSolicitud = (Integer)data.get(PARAM_CODSOLICITUD);

	    // Estableciendo codigo de orden de solicitud generada
	    solicitud.setCodSolicitud(codigoSolicitud);
	    
	    // Obteniendo lista de lineas de orden compra a agregar
	    ListaLineaSolicitud listaLineaSolicitud = solicitud.getListaLineaSolicitud();
	    
	    // Si existen lineas entonces registrarlos
	    if(listaLineaSolicitud != null && listaLineaSolicitud.getLista() != null){
		    // Instanciando variable para llamado de SP
		    SimpleJdbcCall llamarSPLineas = new SimpleJdbcCall(jdbcTemplate).withProcedureName(SP_REGISTRAR_DET_SOLICITUD);
	
		    for (LineaSolicitud item : listaLineaSolicitud.getLista()){
			    // Estableciendo parametros de entrada al SP
			    SqlParameterSource parametrosDetalle = new MapSqlParameterSource()
						    								.addValue(PARAM_CODSOLICITUD, codigoSolicitud)
						    								.addValue(PARAM_DET_CODPRODUCTO , item.getProducto().getCodigo())
						    								.addValue(PARAM_DET_CANTIDAD, item.getCantidad());
			    
			    // Establecer parametros y ejecutar SP
			    Map<String,Object> dataDetalle = llamarSPLineas.execute(parametrosDetalle);
			    
			    // Obteniendo el total de filas afectadas al ejecutar SP
			    resultado += (Integer) dataDetalle.get(TOTAL_FILAS_AFECTADAS);
		    }
	    }
	    
	    // Obteniendo lista de bultos de orden compra a agregar
	    ListaLineaSolicitudBulto listaLineaSolicitudBulto = solicitud.getListaLineaSolicitudBulto();
	    
	    // Si existen bultos entonces registrarlos
	    if(listaLineaSolicitudBulto != null && listaLineaSolicitudBulto.getLista() != null){
		    // Instanciando variable para llamado de SP
		    SimpleJdbcCall llamarSPBultos = new SimpleJdbcCall(jdbcTemplate).withProcedureName(SP_REGISTRAR_DET_SOLICITUD_BULTO);
	
		    for (LineaSolicitudBulto item : listaLineaSolicitudBulto.getLista()){
			    // Estableciendo parametros de entrada al SP
			    SqlParameterSource parametrosDetalleBulto = new MapSqlParameterSource()
						    								.addValue(PARAM_CODSOLICITUD, codigoSolicitud)
						    								.addValue(PARAM_BULTO_CODBULTO , item.getBulto().getCodBulto());
			    
			    // Establecer parametros y ejecutar SP
			    Map<String,Object> dataDetalleBulto = llamarSPBultos.execute(parametrosDetalleBulto);
			    
			    // Obteniendo el total de filas afectadas al ejecutar SP
			    resultado += (Integer) dataDetalleBulto.get(TOTAL_FILAS_AFECTADAS);
			    
			 // Actualizar bulto de solicitud
			    resultado += actualizarEstadoBulto(item.getBulto());
		    }
	    }
	    
	    return resultado > 0;
	}

	private int actualizarEstadoBulto(Bulto bulto){
		logger.info("actualizarEstadoBulto");
		
		// Instanciando variable para llamado de SP
	    SimpleJdbcCall llamarSP = new SimpleJdbcCall(jdbcTemplate).withProcedureName(SP_ACTUALIZAR_ESTADO_BULTO);

	    // Estableciendo parametros de entrada al SP
	    SqlParameterSource parametros = new MapSqlParameterSource()
	    								.addValue(PARAM_BULTO_CODBULTO, bulto.getCodBulto())
	    								.addValue(PARAM_BULTO_ESTADO, bulto.getEstado());
	    
	    // Establecer parametros y ejecutar SP
	    Map<String,Object> data = llamarSP.execute(parametros);
	    
	    // Obteniendo el total de filas afectadas al ejecutar SP
	    int totalRegistrosAfectado = (Integer) data.get(TOTAL_FILAS_AFECTADAS);
	        
	    return totalRegistrosAfectado;
	}
	
	@Override
	public Solicitud obtenerSolicitudItem(Solicitud solicitud) {
		logger.info("obtenerSolicitudItem");

		// Instanciando variable para llamado de SP
	    SimpleJdbcCall llamarSP = new SimpleJdbcCall(jdbcTemplate).withProcedureName(SP_OBTENER_SOLICITUD_ITEM).
	    						  returningResultSet(LISTADO, new RowMapper<Solicitud>(){
									@Override
									public Solicitud mapRow(final ResultSet rs, final int numRow) throws SQLException
								    {
								        final Solicitud solicitud = new Solicitud();
								        solicitud.setCodSolicitud(rs.getInt(CODSOLICITUD));
								        
								        Tienda tiendaOrigen =  new Tienda();
								        tiendaOrigen.setCodigo(rs.getInt(CODTIENDAORIGEN));
								        tiendaOrigen.setNombre(rs.getString(TIENDA_ORIGEN_NOMBRE));
								        solicitud.setTiendaOrigen(tiendaOrigen);
								        
								        Tienda tiendaDestino =  new Tienda();
								        tiendaDestino.setCodigo(rs.getInt(CODTIENDADESTINO));
								        tiendaDestino.setNombre(rs.getString(TIENDA_DESTINO_NOMBRE));
								        solicitud.setTiendaDestino(tiendaDestino);
								        
								        solicitud.setTipo(rs.getString(TIPO));
								        
								        Usuario usuario = new Usuario();
								        usuario.setCodUsuario(rs.getInt(CODUSUARIO));
								        usuario.setNombresyApellidos(rs.getString(USUARIO_NOMBRESYAPELLIDOS));
								        solicitud.setUsuario(usuario);
								        
								        Usuario usuarioAprovacion = new Usuario();
								        usuarioAprovacion.setCodUsuario(rs.getInt(CODUSUARIOAPROVACION));
								        solicitud.setUsuarioAprovacion(usuarioAprovacion);
								        
								        solicitud.setFechaVencimiento(rs.getString(FECHAVENCIMIENTO));
								        solicitud.setObservacion(rs.getString(OBSERVACION));
								        
								        solicitud.setEstado(rs.getString(ESTADO));
								        solicitud.setFechaRegistro(rs.getDate(FECHAREGISTRO).toString());
								        solicitud.setFechaAprovacion(rs.getDate(FECHAAPROVACION)==null?null:rs.getDate(FECHAAPROVACION).toString());
								        return solicitud;
								    }
	    						  }
								 )
								 .returningResultSet(LISTADO_LINEAS, new RowMapper<LineaSolicitud>(){
									@Override
									public LineaSolicitud mapRow(final ResultSet rs, final int numRow) throws SQLException
								    {
								        final LineaSolicitud lineaSolicitud = new LineaSolicitud();
								        lineaSolicitud.setCodigoSolicitud(rs.getInt(CODSOLICITUD));
								        
								        Producto producto = new Producto();
								        producto.setCodigo(rs.getInt(DET_CODPRODUCTO));
								        producto.setCodProductoProveedor(rs.getString(DET_CODPRODUCTOPROVEEDOR));
								        producto.setDescripcion(rs.getString(PRODUCTO_DESCRIPCION));
								        lineaSolicitud.setProducto(producto);
								        
								        lineaSolicitud.setCantidad(rs.getInt(DET_CANTIDAD));
	
								        return lineaSolicitud;
								    }
	    						 }
								 )
	    						  .returningResultSet(LISTADO_LINEAS_ITEM, new RowMapper<LineaSolicitudItem>(){
										@Override
										public LineaSolicitudItem mapRow(final ResultSet rs, final int numRow) throws SQLException
									    {
									        final LineaSolicitudItem lineaSolicitudItem = new LineaSolicitudItem();
									        lineaSolicitudItem.setCodSolicitud(rs.getInt(CODSOLICITUD));
									        
									        Item item = new Item();
									        item.setCodItem(rs.getInt(ITEM_CODITEM));
									        item.setCodificacion(rs.getString(ITEM_CODIFICACION));
									        item.setPrecioCompra(rs.getDouble(ITEM_PRECIOCOMPRA));
									        item.setEstado(rs.getString(ITEM_ESTADO));
									        
									        Tienda tienda = new Tienda();
									        tienda.setCodigo(rs.getInt(ITEM_CODTIENDA));
									        item.setTienda(tienda);
									        
									        Moneda moneda = new Moneda();
									        moneda.setCodigo(rs.getInt(ITEM_CODMONEDA));
									        item.setMoneda(moneda);
									        
									        Producto producto = new Producto();
									        producto.setCodigo(rs.getInt(DET_CODPRODUCTO));
									        producto.setDescripcion(rs.getString(PRODUCTO_DESCRIPCION));
									        item.setProducto(producto);
									        
									        lineaSolicitudItem.setItem(item); 								        
	
									        return lineaSolicitudItem;
									    }
		    						  });

	    // Estableciendo parametros de entrada al SP
	    SqlParameterSource parametros = new MapSqlParameterSource()
	    								.addValue(PARAM_CODSOLICITUD, solicitud.getCodSolicitud()); 

	    // Establecer parametros y ejecutar SP
        Map<String,Object> data = llamarSP.execute(parametros);

        // Obteniendo lista generada de ejecutar SP
 		@SuppressWarnings("unchecked")
 		List<Solicitud> listaSolicitud = (List<Solicitud>)data.get(LISTADO);
         
 		// Declarando objeto solicitud Obtenido
 		Solicitud solicitudObtenido = null;
 		
 		if (logger.isDebugEnabled() && listaSolicitud != null)
        {
            logger.debug("size=" + listaSolicitud.size());
        }
 		
 		if (listaSolicitud != null && listaSolicitud.size()>0){
 			// Obteniendo el primer elemento de la lista de Solicitud
 			solicitudObtenido = listaSolicitud.get(0);
 		
	        // Obteniendo lista de lineas generada de ejecutar SP
			@SuppressWarnings("unchecked")
			List<LineaSolicitud> listaLineaSolicitud = (List<LineaSolicitud>)data.get(LISTADO_LINEAS);
	        
			// Instanciando objeto ListaLineaSolicitud
			ListaLineaSolicitud listaLineaSolicitudResultado = new ListaLineaSolicitud();
	        // Estableciendo resultado al objeto listaLineaSolicitudResultado
			listaLineaSolicitudResultado.setLista(listaLineaSolicitud);
	        
			// --------------------------------------------------------------------------------------------
			// Obteniendo lista de lineas-item generada de ejecutar SP
			@SuppressWarnings("unchecked")
			List<LineaSolicitudItem> listaLineaSolicitudItem = (List<LineaSolicitudItem>)data.get(LISTADO_LINEAS_ITEM);
			
			for (LineaSolicitud lineaSolicitud : listaLineaSolicitudResultado.getLista()){
				
				// Instanciando objeto ListaLineaSolicitudItem
				ListaLineaSolicitudItem listaLineaSolicitudItemResultado =  new ListaLineaSolicitudItem();
				
				for(LineaSolicitudItem lineaSolicitudItem : listaLineaSolicitudItem){
					if( lineaSolicitudItem.getItem().getProducto() == lineaSolicitud.getProducto()){
						listaLineaSolicitudItemResultado.add(lineaSolicitudItem);
					}
				}
			
				if(listaLineaSolicitudItemResultado.size()>0){
					lineaSolicitud.setListaLineaSolicitudItem(listaLineaSolicitudItemResultado);
				}
			}
			// --------------------------------------------------------------------------------------------
			
			// Asignando lista de lineas al objeto Solicitud creado
			solicitudObtenido.setListaLineaSolicitud(listaLineaSolicitudResultado);
			
	        if (logger.isDebugEnabled() && listaLineaSolicitudResultado != null)
	        {
	            logger.debug("sizeLineas=" + listaLineaSolicitudResultado.size());
	        }
 		}

		return solicitudObtenido;
	}
	
	@Override
	public boolean registrarSolicitudItem(Solicitud solicitud) {
		logger.info("registrarSolicitudItem");
		
		int resultado = 0;
		
		// Instanciando variable para llamado de SP Eliminar items registrados en transferencia pasadas
	    SimpleJdbcCall llamarSPLimpiarItemsSolicitud = new SimpleJdbcCall(jdbcTemplate).withProcedureName(SP_LIMPIAR_DET_SOLICITUD_ITEM);
	    // Agregar parametro codigo de cliente
	    llamarSPLimpiarItemsSolicitud.execute(new MapSqlParameterSource()
										     .addValue(PARAM_CODSOLICITUD, solicitud.getCodSolicitud()));
		
		// Obteniendo lineas de la Solicitud
	    ListaLineaSolicitud listaLineaSolicitud = solicitud.getListaLineaSolicitud();
		
		for (LineaSolicitud lineaSolicitud : listaLineaSolicitud.getLista()){
		    for (LineaSolicitudItem lineaSolicitudItem : lineaSolicitud.getListaLineaSolicitudItem().getLista()){
		        // Instanciando variable para llamado de SP
		        SimpleJdbcCall llamarSP = new SimpleJdbcCall(jdbcTemplate).withProcedureName(SP_REGISTRAR_DET_SOLICITUD_ITEM);

		        // Estableciendo parametros de entrada al SP
		        SqlParameterSource parametros = new MapSqlParameterSource()
	    								.addValue(PARAM_CODSOLICITUD, lineaSolicitud.getCodigoSolicitud())
	    								.addValue(PARAM_ITEM_CODITEM, lineaSolicitudItem.getItem().getCodItem());
	    
		        // Establecer parametros y ejecutar SP
		        Map<String,Object> data = llamarSP.execute(parametros);
	    
		        // Obteniendo el total de filas afectadas al ejecutar SP
		        resultado += (Integer) data.get(TOTAL_FILAS_AFECTADAS);
                // Actualizar Item de prestamo
			    resultado += actualizarEstadoItem(lineaSolicitudItem.getItem());
	    	}
	    }
		 return resultado > 0;
	}
	
	private int actualizarEstadoItem(Item item){
		logger.info("actualizarEstadoItem");
		
		// Instanciando variable para llamado de SP
	    SimpleJdbcCall llamarSP = new SimpleJdbcCall(jdbcTemplate).withProcedureName(SP_ACTUALIZAR_ESTADO_ITEM);

	    // Estableciendo parametros de entrada al SP
	    SqlParameterSource parametros = new MapSqlParameterSource()
	    								.addValue(PARAM_ITEM_CODITEM, item.getCodItem())
	    								.addValue(PARAM_ITEM_ESTADO, item.getEstado());
	    
	    // Establecer parametros y ejecutar SP
	    Map<String,Object> data = llamarSP.execute(parametros);
	    
	    // Obteniendo el total de filas afectadas al ejecutar SP
	    int totalRegistrosAfectado = (Integer) data.get(TOTAL_FILAS_AFECTADAS);
	        
	    return totalRegistrosAfectado;
	}
	@Override
	public int modificarSolicitud(Solicitud solicitud){
		logger.info("modificarSolicitud");
		
		// Instanciando variable para llamado de SP
	    SimpleJdbcCall llamarSP = new SimpleJdbcCall(jdbcTemplate).withProcedureName(SP_MODIFICAR_SOLICITUD);

	    // Estableciendo parametros de entrada al SP
	    SqlParameterSource parametros = new MapSqlParameterSource()
	    								.addValue(PARAM_CODSOLICITUD, solicitud.getCodSolicitud())
	    								.addValue(PARAM_ESTADO, solicitud.getEstado())
	    								.addValue(PARAM_CODTIENDAORIGEN, solicitud.getTiendaOrigen().getCodigo())
	    								.addValue(PARAM_FECHAVENCIMIENTO, solicitud.getFechaVencimiento())
	    								.addValue(PARAM_OBSERVACION, solicitud.getObservacion())
	    								.addValue(PARAM_CODUSUARIOAPROVACION, solicitud.getUsuarioAprovacion().getCodUsuario())
	    								.addValue(PARAM_FECHAAPROVACION, solicitud.getFechaAprovacion());
	    
	    // Establecer parametros y ejecutar SP
	    Map<String,Object> data = llamarSP.execute(parametros);
	    
	    // Obteniendo el total de filas afectadas al ejecutar SP
	    int totalRegistrosAfectado = (Integer) data.get(TOTAL_FILAS_AFECTADAS);
	        
	    return totalRegistrosAfectado;
	}
	
	public int actualizarEstadoSolicitud(Solicitud solicitud){
		logger.info("actualizarEstadoSolicitud");
		
		// Instanciando variable para llamado de SP
	    SimpleJdbcCall llamarSP = new SimpleJdbcCall(jdbcTemplate).withProcedureName(SP_ACTUALIZAR_ESTADO_SOLICITUD);

	    // Estableciendo parametros de entrada al SP
	    SqlParameterSource parametros = new MapSqlParameterSource()
	    								.addValue(PARAM_CODSOLICITUD, solicitud.getCodSolicitud())
	    								.addValue(PARAM_ESTADO, solicitud.getEstado());
	    
	    // Establecer parametros y ejecutar SP
	    Map<String,Object> data = llamarSP.execute(parametros);
	    
	    // Obteniendo el total de filas afectadas al ejecutar SP
	    int totalRegistrosAfectado = (Integer) data.get(TOTAL_FILAS_AFECTADAS);
	        
	    return totalRegistrosAfectado;
	}
	
	public int limpiarSolicitudDetalle(Solicitud solicitud){
		logger.info("limpiarSolicitudDetalle");
        
		int resultado = 0;
		
		// Instanciando variable para llamado de SP Eliminar items registrados en transferencia pasadas
	    SimpleJdbcCall llamarSPLimpiarSolicitudDetalle = new SimpleJdbcCall(jdbcTemplate).withProcedureName(SP_LIMPIAR_DET_SOLICITUD);
	    // Agregar parametro codigo de cliente
	    llamarSPLimpiarSolicitudDetalle.execute(new MapSqlParameterSource()
										     .addValue(PARAM_CODSOLICITUD, solicitud.getCodSolicitud()));
    		    
	    return resultado;
	}
	
	public int registrarSolicitudDetalle(Solicitud solicitud){
		logger.info("registrarSolicitudDetalle");
		
		int totalRegistrosAfectado = 0;
		
		// Obteniendo lista de lineas de la Solicitud a agregar
	    ListaLineaSolicitud listaLineaSolicitud = solicitud.getListaLineaSolicitud();
	    
		// Si existen lineas entonces registrarlos
	    if(listaLineaSolicitud != null && listaLineaSolicitud.getLista() != null){
	    // Instanciando variable para llamado de SP
	    SimpleJdbcCall llamarSPLineas = new SimpleJdbcCall(jdbcTemplate).withProcedureName(SP_REGISTRAR_DET_SOLICITUD);
        
	    for (LineaSolicitud lineaSolicitud : listaLineaSolicitud.getLista()){
		     // Estableciendo parametros de entrada al SP
			    SqlParameterSource parametrosDetalle = new MapSqlParameterSource()
						    								.addValue(PARAM_CODSOLICITUD, solicitud.getCodSolicitud())
						    								.addValue(PARAM_DET_CODPRODUCTO , lineaSolicitud.getProducto().getCodigo())
						    								.addValue(PARAM_DET_CANTIDAD, lineaSolicitud.getCantidad());
			    
			    // Establecer parametros y ejecutar SP
			    Map<String,Object> dataDetalle = llamarSPLineas.execute(parametrosDetalle);
			    
			    // Obteniendo el total de filas afectadas al ejecutar SP
			    totalRegistrosAfectado += (Integer) dataDetalle.get(TOTAL_FILAS_AFECTADAS);
		    }
	    }
	    
	    return totalRegistrosAfectado;
	}
	
	public int limpiarSolicitudDetalleBulto(Solicitud solicitud){
		logger.info("limpiarSolicitudDetalle");
        
		int resultado = 0;
		
		// Instanciando variable para llamado de SP Eliminar items registrados en transferencia pasadas
	    SimpleJdbcCall llamarSPLimpiarSolicitudDetalle = new SimpleJdbcCall(jdbcTemplate).withProcedureName(SP_LIMPIAR_DET_SOLICITUD_BULTO);
	    // Agregar parametro codigo de cliente
	    llamarSPLimpiarSolicitudDetalle.execute(new MapSqlParameterSource()
										     .addValue(PARAM_CODSOLICITUD, solicitud.getCodSolicitud()));
    		    
	    return resultado;
	}
	
	public int registrarSolicitudDetalleBulto(Solicitud solicitud){
		logger.info("registrarSolicitudDetalleBulto");
		
		int totalRegistrosAfectado = 0;
		
		//Obteniendo lista de bultos de orden compra a agregar
	    ListaLineaSolicitudBulto listaLineaSolicitudBulto = solicitud.getListaLineaSolicitudBulto();
	    
	 // Si existen bultos entonces registrarlos
	    if(listaLineaSolicitudBulto != null && listaLineaSolicitudBulto.getLista() != null){
		    // Instanciando variable para llamado de SP
		    SimpleJdbcCall llamarSPBultos = new SimpleJdbcCall(jdbcTemplate).withProcedureName(SP_REGISTRAR_DET_SOLICITUD_BULTO);
	
		    for (LineaSolicitudBulto lineaSolicitudBulto : listaLineaSolicitudBulto.getLista()){
			    // Estableciendo parametros de entrada al SP
		    SqlParameterSource parametrosDetalleBulto = new MapSqlParameterSource()
					    								.addValue(PARAM_CODSOLICITUD,  solicitud.getCodSolicitud())
					    								.addValue(PARAM_BULTO_CODBULTO , lineaSolicitudBulto.getBulto().getCodBulto());
		    
		        // Establecer parametros y ejecutar SP
		        Map<String,Object> dataDetalleBulto = llamarSPBultos.execute(parametrosDetalleBulto);

			    // Obteniendo el total de filas afectadas al ejecutar SP
			    totalRegistrosAfectado += (Integer) dataDetalleBulto.get(TOTAL_FILAS_AFECTADAS);
			    
			    // Actualizar bulto de solicitud
			    totalRegistrosAfectado += actualizarEstadoBulto(lineaSolicitudBulto.getBulto());
		    }
	    }
	    
	    return totalRegistrosAfectado;	   
	  
	}
	
	
	
    

	
	public int actualizarSolicitud(Solicitud solicitud) {
		logger.info("actualizarSolicitud");

		// Instanciando variable para llamado de SP
		SimpleJdbcCall llamarSP = new SimpleJdbcCall(jdbcTemplate)
				.withProcedureName(SP_ACTUALIZAR_SOLICITUD);
		
		
		// Estableciendo parametros de entrada al SP
		SqlParameterSource parametros = new MapSqlParameterSource()
				.addValue(PARAM_CODSOLICITUD, solicitud.getCodSolicitud())
				.addValue(PARAM_ESTADO, solicitud.getEstado())
				.addValue(PARAM_FECHAVENCIMIENTO, solicitud.getFechaVencimiento())
				.addValue(PARAM_OBSERVACION, solicitud.getObservacion())
				.addValue(PARAM_FECHAAPROVACION, solicitud.getFechaAprovacion())
				.addValue(PARAM_CODUSUARIOAPROVACION, solicitud.getUsuarioAprovacion().getCodUsuario())
				.addValue(PARAM_CODTIENDADESTINO, solicitud.getTiendaDestino().getCodigo());
	
		// Establecer parametros y ejecutar SP
		Map<String, Object> data = llamarSP.execute(parametros);

		// Obteniendo el total de filas afectadas al ejecutar SP
		int totalRegistrosAfectado = (Integer) data.get(TOTAL_FILAS_AFECTADAS);
		// ---------------------------------------------------------------------------
		// Obteniendo lista de item
		ListaLineaSolicitudBulto listaLineaSolicitudBulto = solicitud.getListaLineaSolicitudBulto();

		// Si existen items entonces asociarlos
		if (listaLineaSolicitudBulto != null && listaLineaSolicitudBulto.getLista() != null) {

			for (LineaSolicitudBulto lineaSolicitudBulto : listaLineaSolicitudBulto.getLista()) {

				// Actualizar Item de prestamo
				totalRegistrosAfectado += actualizarEstadoBulto(lineaSolicitudBulto.getBulto());
			}
		}
		// -----------------------------------------------------------------------------
		return totalRegistrosAfectado;
	}
	
	public int actualizarObservacionesSolicitud(Solicitud solicitud) {
		logger.info("actualizarObservacionesSolicitud");

		// Instanciando variable para llamado de SP
		SimpleJdbcCall llamarSP = new SimpleJdbcCall(jdbcTemplate)
				.withProcedureName(SP_ACTUALIZAR_OBSERVACIONES_SOLICITUD);
		
		
		// Estableciendo parametros de entrada al SP
		SqlParameterSource parametros = new MapSqlParameterSource()
				.addValue(PARAM_CODSOLICITUD, solicitud.getCodSolicitud())
				.addValue(PARAM_OBSERVACION, solicitud.getObservacion())
				.addValue(PARAM_CODUSUARIOAPROVACION, solicitud.getUsuarioAprovacion().getCodUsuario());
	
		// Establecer parametros y ejecutar SP
		Map<String, Object> data = llamarSP.execute(parametros);

		// Obteniendo el total de filas afectadas al ejecutar SP
		int totalRegistrosAfectado = (Integer) data.get(TOTAL_FILAS_AFECTADAS);
			return totalRegistrosAfectado;		
		    
	}
}
